home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / C / Applications / Portable Patmos / src / portable kernel / ncsasock / socket.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-23  |  40.5 KB  |  1,696 lines  |  [TEXT/R*ch]

  1. /*
  2.  * BSD-style socket emulation library for the Mac
  3.  * Original author: Tom Milligan
  4.  * Current author: Charlie Reiman - creiman@ncsa.uiuc.edu
  5.  *
  6.  * This source file is placed in the public domian.
  7.  * Any resemblance to NCSA Telnet, living or dead, is purely coincidental.
  8.  *
  9.  *      National Center for Supercomputing Applications
  10.  *      152 Computing Applications Building
  11.  *      605 E. Springfield Ave.
  12.  *      Champaign, IL  61820
  13.  */
  14.  
  15. /*
  16.  *
  17.  *    The following calls are implemented
  18.  *
  19.  *        socket
  20.  *        bind
  21.  *        listen
  22.  *        accept
  23.  *        connect
  24.  *        read
  25.  *        recv
  26.  *        recvfrom
  27.  *        write
  28.  *        writev
  29.  *        send
  30.  *        sendto
  31.  *        select
  32.  *        close
  33.  *        getdtablesize
  34.  *        getsockname
  35.  *        getpeername
  36.  *        shutdown
  37.  *        fcntl(F_DUPFD)
  38.  *        fcntl(F_GETFL)
  39.  *        fcntl(F_SETFL,FNDELAY)
  40.  *        dup
  41.  *        dup2
  42.  *        ioctl(FIONBIO)
  43.  *        ioctl(FIONREAD)
  44.  *
  45.  *    Non-blocking I/O is supported. All calls which would block return
  46.  *    immediately with an 'error' indicating so. Select() may be used to
  47.  *    determine when an operation can be performed.
  48.  *
  49.  *    Ioctl(FIONBIO) or fcntl(F_SETFL,FNDELAY)  can be used to toggle or set
  50.  *  the blocking status of a socket.
  51.  *
  52.  *    In a blocking situation, accept() and read() return EWOULDBLOCK and 
  53.  *    refuse to do anything. Select() for read() to learn when a incoming 
  54.  *    connection is available. 
  55.  *
  56.  *    Connect() and write() (which shouldn't take too long anyway) start 
  57.  *    the operation and return EINPROGRESS. Select for write() to learn
  58.  *    when connect() has completed. Write() on a socket which is still
  59.  *    'inprogress' return EALREADY.
  60.  *
  61.  *
  62.  *    Socket operations are single threaded and half-duplex. Fixing this is
  63.  *    left as an execise for the reader. Shouldn't be a terrible problem
  64.  *    anyway. Read() never blocks and write() only blocks for long if there
  65.  *    is a problem.
  66.  *
  67.  *    Calls which find the socket busy will return EALREADY. These are
  68.  *    read() or write() with a connect() or write() in progress.
  69.  *
  70.  *
  71.  *    Socket options are not supported. Hence no setsockopt() and getsockopt() 
  72.  *    calls.
  73.  *
  74.  *
  75.  *  CR: I attempted to support OOB data for send and recv, but not promises are
  76.  *  made as I didn't have any immediate tests for them.
  77.  *
  78.  *
  79.  *    Readv() is not implemented.
  80.  *
  81.  *
  82.  *    All calls which encounter an error will set the global variable errno
  83.  *    to indicate the problem. Some common values for errno are...
  84.  *
  85.  *        EBADF        the socket parameter is not a valid socket descriptor.
  86.  *        
  87.  *        EFAULT       a pointer parameters is rubbish.
  88.  *        
  89.  *        EINVAL       a non-pointer parameters is rubbish.
  90.  *
  91.  *        ENOTCONN     the socket should be in a connected state for this 
  92.  *                   operation, but isn't.
  93.  *
  94.  *        EISCONN      the socket is already connected.
  95.  *
  96.  * ----------------- non-blocking I/O
  97.  *
  98.  *        EWOULDBLOCK  accept() or one of the read() calls would block. 
  99.  *
  100.  *        EINPROGRESS  connect() or one of the write() operations has been 
  101.  *                   started.
  102.  *
  103.  * ----------------- SINGLE THREAD
  104.  *
  105.  *        EALREADY     an operation is already in progress on the socket.
  106.  *
  107.  * ----------------
  108.  *
  109.  *        EBUG           an internal error occured.
  110.  */
  111.  
  112. #ifdef USEDUMP
  113. # pragma load "socket.dump"
  114.  
  115. #else
  116. # include <Events.h>
  117. # include <Types.h>
  118. # include <Stdio.h>
  119. # include <string.h>
  120. # include <s_types.h>
  121. # include <neti_in.h>
  122. # include <neterrno.h>
  123. # include <s_file.h>
  124. # include <s_ioctl.h>
  125. # include <s_socket.h>
  126. # include <s_time.h>
  127. # include <s_uio.h>
  128.  
  129. # include "sock_str.h"
  130. # include "sock_int.h"
  131.  
  132. #endif
  133.  
  134. #include "sock_ext.h"
  135.  
  136.  
  137. /*
  138.  *   GET YOUR GLOBALS HERE!
  139.  */
  140.  
  141. int defaultSpin(spin_msg msg,long param);
  142. SocketPtr sockets = NULL;            /* The socket table. */
  143. AllPb *pbList = NULL;                /* The pb array */
  144. short pbLast = 0;                    /* last pb used */
  145. StreamHashEntPtr streams = NULL;    /* The streams hash table */
  146. SpinFn spinroutine = (SpinFn) defaultSpin;    /* The spin routine. */ 
  147.  
  148. /*
  149.  *    s_socket(domain, type, protocol)
  150.  *
  151.  *        socket creates a MacTCP socket and returns a descriptor.
  152.  *                 
  153.  *        Domain must be AF_INET
  154.  *         
  155.  *        Type may be SOCK_STREAM to create a TCP socket or 
  156.  *        SOCK_DGRAM to create a UDP socket.
  157.  *                 
  158.  *        Protocol is ignored. (isn't it always?)
  159.  *                 
  160.  *        TCP sockets provide sequenced, reliable, two-way connection
  161.  *        based byte streams.
  162.  *
  163.  *        A TCP socket must be in a connected
  164.  *        state before any data may be sent or received on it. A 
  165.  *        connection to another socket is created with a connect() call
  166.  *        or the listen() and accept() calls.
  167.  *        Once connected, data may be transferred using read() and
  168.  *        write() calls or some variant of the send() and recv()
  169.  *        calls. When a session has been completed a close() may  be
  170.  *        performed.
  171.  *
  172.  *        
  173.  *        A UDP socket supports the exchange of datagrams (connectionless, 
  174.  *        unreliable messages of a fixed maximum length) with  
  175.  *        correspondents named in send() calls. Datagrams are
  176.  *        generally received with recv(), which returns the next
  177.  *        datagram with its return address.
  178.  *
  179.  *        An fcntl() or ioctl() call can be used to enable non-blocking I/O.
  180.  *
  181.  *        The return value is a descriptor referencing the socket or -1
  182.  *        if an error occurs, in which case global variable errno is
  183.  *        set to one of:
  184.  *
  185.  *            ENOMEM                Failed to allocate memory for the socket
  186.  *                              data structures.
  187.  *        
  188.  *            EAFNOSUPPORT         Domain wasn't AF_INET.
  189.  *
  190.  *            ESOCKTNOSUPPORT     Type wasn't SOCK_STREAM or SOCK_DGRAM.
  191.  *
  192.  *            EMFILE              The socket descriptor table is full.
  193.  */
  194. int s_socket(
  195.     Int4 domain,
  196.     Int4 type,
  197.     short protocol)
  198. {
  199.     SocketPtr sp;
  200.     int s;
  201.  
  202. #if    SOCK_DEBUG >= 3
  203.     dprintf("s_socket:\n");
  204. #endif
  205.  
  206.     sock_init();
  207.     
  208.     /*
  209.      * Support only Internet family
  210.      */
  211.     if ((domain != AF_INET) && (domain != AF_UNIX))
  212.         return(sock_err(EAFNOSUPPORT));
  213.         
  214.     switch(type) 
  215.     {
  216.         case SOCK_DGRAM:
  217.             protocol = IPPROTO_UDP;
  218.             break;
  219.         case SOCK_STREAM:
  220.             protocol = IPPROTO_TCP;
  221.             break;
  222.         default:
  223.             return(sock_err(ESOCKTNOSUPPORT));
  224.     }
  225.         
  226.     /*
  227.      *    Create a socket table entry 
  228.      */
  229.     s = sock_free_fd(0);        /* Get next free file descriptor */
  230.     if (s == -1)
  231.         return(sock_err(EMFILE));
  232.     sp = sockets+s;
  233.     sp->fd = s;
  234.     sp->protocol = protocol;
  235.     bzero(&sp->sa, sizeof(struct sockaddr_in));
  236.     bzero(&sp->peer, sizeof(struct sockaddr_in));
  237.     sp->sa.sin_family        = AF_INET;
  238.     sp->sa.sin_len            = sizeof(struct sockaddr_in);
  239.     sp->status                = SOCK_STATUS_USED;
  240.     sp->nonblocking            = false;
  241.  
  242.  
  243.     /* Create a new stream on the socket. */
  244.     switch(sp->protocol) 
  245.     {
  246.         case IPPROTO_UDP:
  247.             /* udp streams are not created until the last minute */
  248.             /* because we dont know if the caller wants to assign */
  249.             /* a special port number yet (via bind) and mactcp */
  250.             /* assigns udp port numbers at stream creation */
  251.             sp->sstate = SOCK_STATE_NO_STREAM;
  252.             break;
  253.  
  254.         case IPPROTO_TCP:
  255.             /* the tcp stream is created now because tcp port numbers */
  256.             /* are assigned during active/passiveOpen which is done */
  257.             /* during listen or connect */
  258.             sp->sstate = SOCK_STATE_UNCONNECTED;
  259.             if (sock_tcp_new_stream(sp) < 0)
  260.                 return(-1); /* sock_err already called */
  261.     }
  262.  
  263.     return(s);
  264. }
  265.  
  266.  
  267. /*
  268.  *    s_bind(s, name, namelen)
  269.  *
  270.  *        bind requests that the name (ip address and port) pointed to by 
  271.  *        name be assigned to the socket s.
  272.  *        
  273.  *        The return value is 0 on success or -1 if an error occurs,
  274.  *        in which case global variable errno is set to one of:
  275.  *
  276.  *        EAFNOSUPPORT        The address family in name is not AF_INET.
  277.  *        
  278.  *        EINVAL              The socket is already bound to an address.
  279.  *        
  280.  *        EADDRNOTAVAIL       The specified address is  not  available
  281.  *                             from the local machine. ie. the address
  282.  *                            portion of name was not this machine's address.
  283.  *
  284.  *        MacTCP does not separate name binding and connection establishment.
  285.  *        Therefore the port number is not verified, just stored for later use.
  286.  *
  287.  *        If a specific local port is not required, bind is optional in this
  288.  *        implementation.
  289.  */    
  290. int s_bind( 
  291.     Int4 s, 
  292.     struct sockaddr *sa_name,
  293.     Int4 namelen)
  294. {
  295.     SocketPtr sp;
  296.     struct sockaddr_in *name=(struct sockaddr_in *)sa_name;
  297.     
  298. #if    SOCK_DEBUG >= 3
  299.     dprintf("s_bind: bind %d to %08x/%d\n",
  300.         s, name->sin_addr.s_addr, name->sin_port);
  301. #endif
  302.  
  303.     if (! sock_good_fd(s))
  304.         return(sock_err(EBADF));
  305.     sp = sockets+s;
  306.         
  307.     if (namelen < sizeof(struct sockaddr_in))
  308.         return(sock_err(EINVAL));
  309.  
  310.     if (!goodptr(name)) 
  311.         return(sock_err(EFAULT));
  312.  
  313.     if ((name->sin_family != AF_INET) && (name->sin_family != AF_UNIX))
  314.         return(sock_err(EAFNOSUPPORT));
  315.  
  316.     if (sp->sa.sin_port != 0) /* already bound */
  317.         return(sock_err(EINVAL));
  318.  
  319.     /*
  320.      *    If client passed a local IP address, assure it is the right one
  321.      */
  322.     if (name->sin_addr.s_addr != 0) 
  323.     {
  324.         if (name->sin_addr.s_addr != xIPAddr())
  325.             return(sock_err(EADDRNOTAVAIL));
  326.     }
  327.  
  328.     /*
  329.      *    NOTE: can't check a TCP port for EADDRINUSE
  330.      *    just save the address and port away for connect or listen or...
  331.      */
  332.     sp->sa.sin_addr.s_addr = name->sin_addr.s_addr;
  333.     sp->sa.sin_port = name->sin_port;
  334.     return(0);
  335. }
  336.  
  337. /*
  338.  *    s_connect - initiate a connection on a MacTCP socket
  339.  *
  340.  *        If the parameter s is a UDP socket,
  341.  *        then  this  call specifies the address to  which  datagrams
  342.  *        are  to  be  sent, and the only address from which datagrams
  343.  *        are to be received.  
  344.  *             
  345.  *        If it is a TCP socket, then this call attempts to make a 
  346.  *        connection to another socket. The other socket is specified 
  347.  *        by an internet address and port.
  348.  *             
  349.  *        TCP sockets may successfully connect() only once;
  350.  *             
  351.  *        UDP sockets may use connect() multiple times to change
  352.  *        their association. UDP sockets may dissolve the association
  353.  *        by connecting to an invalid address, such as a null
  354.  *        address.
  355.  *        
  356.  *        If the connection or binding succeeds, then 0 is returned.
  357.  *        Otherwise a -1 is returned, and a more specific error code
  358.  *        is stored in errno.
  359.  *        
  360.  *        EAFNOSUPPORT        The address family in addr is not AF_INET.
  361.  *        
  362.  *        EHOSTUNREACH        The TCP connection came up half-way and 
  363.  *                          then failed.
  364.  *             
  365.  *    -------------- some day instead of EHOSTUNREACH -----------------
  366.  *        
  367.  *        EADDRNOTAVAIL       The specified address is not available
  368.  *                            on the remote machine.
  369.  *        
  370.  *        ETIMEDOUT           Connection establishment timed out
  371.  *                            without establishing a connection.
  372.  *        
  373.  *        ECONNREFUSED        The attempt to  connect  was  forcefully
  374.  *                            rejected.
  375.  *        
  376.  *        ENETUNREACH         The network is not reachable from here.
  377.  *        
  378.  *        EHOSTUNREACH        The host is not reachable from here.
  379.  *        
  380.  *        EADDRINUSE          The address is already in use.
  381.  */
  382. int s_connect(
  383.     Int4 s,
  384.     struct sockaddr *sa_addr,
  385.     Int4 addrlen)
  386. {
  387.     SocketPtr sp;
  388.     struct sockaddr_in *addr=(struct sockaddr_in *)sa_addr;
  389.     
  390. #if SOCK_DEBUG >= 2
  391.     dprintf("s_connect: connect %d to %08x/%d\n",
  392.         s, addr->sin_addr.s_addr, addr->sin_port);
  393. #endif
  394.     if (! sock_good_fd(s))
  395.         return(sock_err(EBADF));
  396.         
  397.     if (addrlen != sizeof(struct sockaddr_in))
  398.         return(sock_err(EINVAL));
  399.  
  400.     if (! goodptr(addr))
  401.         return(sock_err(EFAULT));
  402.  
  403.     if (addr->sin_family != AF_INET)
  404.         return(sock_err(EAFNOSUPPORT));
  405.  
  406.     sp = sockets+s;
  407.     switch(sp->protocol) 
  408.     {
  409.         case IPPROTO_UDP:
  410.             return(sock_udp_connect(sp,addr));
  411.  
  412.         case IPPROTO_TCP:
  413.             return(sock_tcp_connect(sp,addr));
  414.     }
  415. }
  416.  
  417. /*
  418.  *    s_listen()
  419.  *
  420.  *        To accept connections, a socket is first created  with
  421.  *        socket(), a backlog for incoming connections is specified
  422.  *        with listen() and then the  connections  are  accepted  with
  423.  *        accept(). The listen() call applies only to TCP sockets.
  424.  *        
  425.  *        The qlen parameter is supposed to define the maximum length
  426.  *        the queue of pending connections may grow to. It is ignored.
  427.  *        
  428.  *        A 0 return value indicates success; -1 indicates an error.
  429.  *        
  430.  *        EOPNOTSUPP          s is not a TCP socket.
  431.  */
  432. int s_listen(
  433.     Int4 s,
  434.     Int4 qlen)
  435. {
  436. #pragma unused(qlen)
  437.     SocketPtr sp;
  438.     
  439. #if SOCK_DEBUG >= 2
  440.     dprintf("listen: listen %d\n", s);
  441. #endif
  442.     if (! sock_good_fd(s))
  443.         return(sock_err(EBADF));
  444.         
  445.     sp = sockets+s;    
  446.     switch(sp->protocol) 
  447.     {
  448.         case IPPROTO_UDP:
  449.             return(sock_err(EOPNOTSUPP));
  450.         
  451.         case IPPROTO_TCP:
  452.             return(sock_tcp_listen(sp));
  453.     }
  454. }
  455.  
  456. /*
  457.  *    s_accept(s, addr, addrlen)
  458.  *
  459.  *        s is a socket that has been created with socket,  bind, listen.
  460.  *        
  461.  *        Accept  extracts the  first  connection  on the queue of pending 
  462.  *        connections, creates a new socket with the same properties of s 
  463.  *        and allocates  a  new  file  descriptor,  ns, for the socket.
  464.  *        
  465.  *        If no pending connections are present on the queue, and the socket
  466.  *        is not marked as non-blocking, accept blocks the caller until
  467.  *        a connection is present. 
  468.  *        
  469.  *        If the socket is marked non-blocking  and  no pending connections 
  470.  *        are present on the queue, accept returns an error EWOULDBLOCK.
  471.  *        
  472.  *        The accepted socket, ns, is used to read and write data to and
  473.  *        from the socket which connected to this one; it is not  used
  474.  *        to  accept  more connections.  The original socket s remains
  475.  *        open for accepting further connections.
  476.  *        
  477.  *        The argument addr is a result parameter that  is  filled  in
  478.  *        with  the  address of the connecting socket. The addrlen is 
  479.  *        a value-result  parameter; it should initially contain the
  480.  *        amount of space pointed to by addr; on return it will contain 
  481.  *        the actual length (in bytes) of the address returned.
  482.  *        
  483.  *        This call is used with TCP sockets only.
  484.  *        
  485.  *        It is possible to select a socket  for  the  purposes  of
  486.  *        doing an accept by selecting it for read.
  487.  *
  488.  *        Translation: To check and see if there is a connection pending,
  489.  *        call s_select and check for pending reads.
  490.  *        
  491.  *        The call returns -1 on error.  If it succeeds, it returns  a
  492.  *        non-negative  integer  that is a descriptor for the accepted
  493.  *        socket.
  494.  *        
  495.  *        EOPNOTSUPP          s is not a TCP socket.
  496.  *        
  497.  *        EMFILE              The socket descriptor table is full.
  498.  */
  499. int s_accept(
  500.     Int4 s,
  501.     struct sockaddr *sa_addr,
  502.     Int4 *addrlen)
  503. {
  504.     SocketPtr sp;
  505.     struct sockaddr_in *addr=(struct sockaddr_in *)sa_addr;
  506.  
  507. #if SOCK_DEBUG >= 2
  508.     dprintf("s_accept: %d\n", s);
  509. #endif
  510.     if (! sock_good_fd(s))
  511.         return(sock_err(EBADF));
  512.         
  513.     if (!goodptr(addr) || !goodptr(addrlen)) 
  514.         return(sock_err(EFAULT));
  515.  
  516.     if (*addrlen < 0) 
  517.         return(sock_err(EINVAL));
  518.  
  519.     if (sock_free_fd(0) == -1)
  520.         return(sock_err(EMFILE));
  521.  
  522.     sp = sockets+s;
  523.     switch(sp->protocol) 
  524.     {
  525.         case IPPROTO_UDP:
  526.             return(sock_err(EOPNOTSUPP));
  527.         case IPPROTO_TCP:
  528.             return(sock_tcp_accept(sp,addr,addrlen));
  529.     }
  530. }
  531.  
  532. /*
  533.  * s_accept_once
  534.  *
  535.  * A mac specific routine, designed to compenstate for a bug
  536.  * in MacTCP. If you close a passive, unconnected stream,
  537.  * MacTCP will generate an error. s_accept always creates
  538.  * a new listening (passive open) stream that will eventually
  539.  * need to be closed. s_accept_once does not create a new
  540.  * listening socket. It will return the same socket originally
  541.  * passed to it, and NO more connections will be accepted
  542.  * on the old listening port.
  543.  *
  544.  * Other than that, it is identical to s_accept.
  545.  */
  546. int s_accept_once(
  547.     Int4 s,
  548.     struct sockaddr *sa_addr,
  549.     Int4 *addrlen)
  550. {
  551.     SocketPtr sp;
  552.     struct sockaddr_in *addr=(struct sockaddr_in *)sa_addr;
  553.  
  554. #if SOCK_DEBUG >= 2
  555.     dprintf("s_accept: %d\n", s);
  556. #endif
  557.     if (! sock_good_fd(s))
  558.         return(sock_err(EBADF));
  559.         
  560.     if (!goodptr(addr) || !goodptr(addrlen)) 
  561.         return(sock_err(EFAULT));
  562.  
  563.     if (*addrlen < 0) 
  564.         return(sock_err(EINVAL));
  565.  
  566.     if (sock_free_fd(0) == -1)
  567.         return(sock_err(EMFILE));
  568.  
  569.     sp = sockets+s;
  570.     switch(sp->protocol) 
  571.     {
  572.         case IPPROTO_UDP:
  573.             return(sock_err(EOPNOTSUPP));
  574.         case IPPROTO_TCP:
  575.             {
  576.             int        returnCode;
  577.             
  578.             returnCode=sock_tcp_accept_once(sp,addr,addrlen);
  579.             return (returnCode ? returnCode : s );
  580.             }
  581.     }
  582. }
  583.  
  584. /*
  585.  *    s_close(s)
  586.  *
  587.  *        The close call destroys the socket s. If this is the last reference 
  588.  *        to the underlying MacTCP stream, then the stream will be released.
  589.  *    
  590.  *        A 0 return value indicates success; -1 indicates an error.
  591.  *
  592.  *        NOTE: if non-blocking I/O is enabled EWOULDBLOCK will be returned
  593.  *            if there are TCP writes in progress. (UDP writes are
  594.  *            performed synchronously.)
  595.  *
  596.  *              All reads are terminated and unread data is lost.
  597.  */
  598. int s_close(
  599.     Int4 s)
  600. {
  601.     int t;
  602.     SocketPtr sp;
  603.     int status;
  604.     
  605. #if SOCK_DEBUG >= 2
  606.     dprintf("s_close: %d\n", s);
  607. #endif
  608.     if (! sock_good_fd(s))
  609.         return(sock_err(EBADF));
  610.         
  611.     sp = sockets+s;
  612.  
  613.     /*
  614.      *    Look for duplicates of the socket.  Only close down the connection
  615.      *    if there are no duplicates(i.e. socket not dup'd).
  616.      */
  617.      for (t = 0; t < NUM_SOCKETS; t++) 
  618.      {
  619.          if (t == s)
  620.             continue;
  621.          if (!(sockets[t].status & SOCK_STATUS_USED))
  622.             continue;
  623.         else if (sockets[t].protocol == sp->protocol && sockets[t].stream == sp->stream )
  624.         {    /* found a duplicate */
  625. #if SOCK_DEBUG >= 3
  626.             dprintf("s_close: found a dup at %d(%d, don't close stream\n",
  627.                 t, sockets[t].protocol);
  628. #endif
  629.             sock_clear_fd(s);
  630.             return(0);
  631.         }
  632.     }
  633.  
  634.     /*
  635.      *    No duplicates, close the stream. 
  636.      */
  637.     switch(sp->protocol) 
  638.     {
  639.         case IPPROTO_UDP:
  640.             status = sock_udp_close(sp);
  641.             break;
  642.             
  643.         case IPPROTO_TCP:
  644.             status = sock_tcp_close(sp);
  645.             break;
  646.     }
  647.     if (status != EWOULDBLOCK)
  648.         sock_clear_fd(s);
  649.     return(status);
  650. }
  651.  
  652.  
  653. /*
  654.  *    s_read(s, buffer, buflen)
  655.  *
  656.  *    s_recv(s, buffer, buflen, flags)
  657.  *    
  658.  *    s_recvfrom(s, buffer, buflen, flags, from, fromlen)
  659.  *    
  660.  *        read() attempts to read nbytes of data from the socket s.  
  661.  *        
  662.  *        recv() and recvfrom() attempt to receive a message (ie a datagram) 
  663.  *        on the socket s. 
  664.  *
  665.  *        from returns the address of the socket which sent the message.
  666.  *        fromlen is the usual value-result length parameter. 
  667.  *        
  668.  *        Typically, read() is used with a TCP stream and recv() with
  669.  *        UDP where the idea of a message makes more sense. But in fact,
  670.  *        read() and recv() are equivalent.
  671.  *        
  672.  *        For UDP...
  673.  *            If a message (ie. datagram) is too long to fit in the supplied 
  674.  *            buffer, excess bytes will be discarded..
  675.  *
  676.  *            If no messages are available at the socket, the receive call
  677.  *            waits for a message to arrive, unless the socket is non-
  678.  *            blocking in which case -1 is returned with errno set to 
  679.  *            EWOULDBLOCK.
  680.  *
  681.  *        For TCP...
  682.  *            Regardless of non-blocking status, if less data is available
  683.  *            than has been requested, only that much data is returned.
  684.  *
  685.  *            If the socket is marked for non-blocking I/O, and the socket 
  686.  *            is empty, the operation will fail with the error EWOULDBLOCK.
  687.  *            Otherwise, the operation will block until data is available 
  688.  *            or an error occurs.
  689.  *
  690.  *            A return value of zero indicates that the stream has been
  691.  *            closed and all data has already been read. ie. end-of-file.
  692.  *        
  693.  *        Flags is ignored.
  694.  *        
  695.  *        If successful, the number of bytes actually received is
  696.  *        returned. Otherwise, a -1 is returned and the global variable
  697.  *        errno is set to indicate the error. 
  698.  *        
  699.  *        ESHUTDOWN    The socket has been shutdown for receive operations.
  700.  */
  701. int s_recvfrom(
  702.     Int4 s,
  703.     char *buffer,
  704.     Int4 buflen,
  705.     Int4 flags,
  706.     struct sockaddr *sa_from,
  707.     Int4 *fromlen);
  708.  
  709. int s_read(
  710.     Int4 s,
  711.     char *buffer,
  712.     Int4 buflen)
  713. {
  714.     int fromlen = 0;
  715.     return(s_recvfrom(s, buffer, buflen, 0, NULL, (void *)&fromlen));
  716. }
  717.  
  718. int s_recv(
  719.     Int4 s,
  720.     char *buffer,
  721.     Int4 buflen,
  722.     Int4 flags)
  723. {
  724.     int fromlen = 0;
  725.     return(s_recvfrom(s, buffer, buflen, flags, NULL, (void *)&fromlen));
  726. }
  727.  
  728. int s_recvfrom(
  729.     Int4 s,
  730.     char *buffer,
  731.     Int4 buflen,
  732.     Int4 flags,
  733.     struct sockaddr *sa_from,
  734.     Int4 *fromlen)
  735. {
  736.     SocketPtr sp;
  737.     struct sockaddr_in *from=(struct sockaddr_in *)sa_from;
  738.  
  739. #if SOCK_DEBUG >= 3
  740.     dprintf ("s_recvfrom: %d\n", s);
  741. #endif
  742.     if (s < 0 || s >= NUM_SOCKETS)
  743.         return (sock_err (EBADF));
  744.         
  745.     sp = sockets+s;
  746.     if (! is_used (sp))
  747.         return (sock_err (EBADF));
  748.         
  749.     if (!goodptr(buffer))
  750.         return (sock_err (EFAULT));
  751.         
  752.     if (buflen <= 0)
  753.         return(sock_err(EINVAL));
  754.         
  755.     if (! (from == NULL || goodptr(from)) )
  756.         return(sock_err(EFAULT));
  757.         
  758.     if (! (fromlen == NULL || goodptr(fromlen)) )
  759.         return(sock_err(EFAULT));
  760.     else
  761.         if ( *fromlen < 0 )
  762.             return(sock_err(EINVAL));
  763.  
  764.     if (sock_noread(sp))
  765.         return(sock_err(ESHUTDOWN));
  766.  
  767.     switch(sp->protocol) 
  768.     {
  769.         case IPPROTO_UDP:
  770.             return(sock_udp_recv(sp, buffer, buflen, flags, from, (int *)fromlen));
  771.  
  772.         case IPPROTO_TCP:
  773.             return(sock_tcp_recv(sp, buffer, buflen, flags));
  774.     }
  775. }
  776.  
  777.  
  778. /*
  779.  *    s_write(s, buffer, buflen)
  780.  *
  781.  *    s_writev(s, iov, iovcnt)
  782.  *
  783.  *    s_send(s, buffer, buflen, flags)
  784.  *
  785.  *    s_sendto(s, buffer, buflen, flags, to, tolen)
  786.  *
  787.  *        write() attempts to write nbytes of data to the socket s from
  788.  *        the buffer pointed to by buffer.
  789.  *        
  790.  *        writev() gathers the output data from the buffers specified 
  791.  *        by the members of the iov array. Each iovec entry specifies 
  792.  *        the base address and length of an area in memory from which 
  793.  *        data should be written.
  794.  *        
  795.  *        send() and sendto() are used to transmit a message to another 
  796.  *        socket on the socket s.
  797.  *
  798.  *        Typically, write() is used with a TCP stream and send() with
  799.  *        UDP where the idea of a message makes more sense. But in fact,
  800.  *        write() and send() are equivalent.
  801.  *        
  802.  *        For UDP...
  803.  *
  804.  *          Write() and send() operations are completed as soon as the
  805.  *          data is placed on the transmission queue.???????
  806.  *
  807.  *            The address of the target is given by to.
  808.  *
  809.  *            The message must be short enough to fit into one datagram.
  810.  *        
  811.  *            Buffer space must be available to hold the message to be 
  812.  *            transmitted, regardless of its non-blocking I/O state.
  813.  *        
  814.  *        For TCP...
  815.  *            Write() and send() operations are not considered complete
  816.  *            until all data has been sent and acknowledged.
  817.  *
  818.  *            If a socket is marked for non-blocking I/O, the operation
  819.  *            will return an 'error' of EINPROGRESS.
  820.  *        
  821.  *            If the socket is not marked for non-blocking I/O, the write will
  822.  *            block until space becomes available.
  823.  *        
  824.  *        write() and send() may be used only when the socket is in a connected
  825.  *        state, sendto() may be used at any time.
  826.  *
  827.  *        Flags is ignored.
  828.  *        
  829.  *        These calls return the number of bytes sent, or -1 if an error 
  830.  *        occurred.
  831.  *        
  832.  *        EINVAL           The sum of the iov_len values in the iov array was
  833.  *                         greater than 65535 (TCP) or 65507 (UDP) or there
  834.  *                       were too many entries in the array (16 for TCP or
  835.  *                       6 for UDP).
  836.  *
  837.  *        ESHUTDOWN        The socket has been shutdown for send operations.
  838.  *        
  839.  *        EMSGSIZE         The message is too big to send in one datagram. (UDP)
  840.  *
  841.  *        ENOBUFS          The transmit queue is full. (UDP)
  842.  */
  843.  
  844. int s_really_send(
  845.     Int4 s,
  846.     char *buffer,
  847.     Int4 count,
  848.     Int4 flags,
  849.     struct sockaddr_in *to);
  850.  
  851. int s_write(
  852.     Int4 s,
  853.     char *buffer,
  854.     Int4 buflen)
  855. {
  856.     return(s_really_send(s, buffer, buflen, 0, NULL));
  857.  
  858. int s_writev(
  859.     Int4 s,
  860.     struct iovec *iov,
  861.     Int4 count)
  862. {    
  863.     int        result,tally=0;
  864.     
  865.     while (count--)
  866.         {
  867.         if ( !goodptr( iov ) )
  868.             return sock_err(EFAULT);
  869.         result= s_really_send(s, (char *)(iov->iov_base),
  870.                 (int)(iov->iov_len), 0, NULL);
  871.         if (result < 0)
  872.             return sock_err(result);
  873.         iov++;
  874.         tally+=result;
  875.         }
  876.     return tally;
  877.  
  878. int s_send(
  879.     Int4 s,
  880.     char *buffer,
  881.     Int4 buflen,
  882.     Int4 flags)
  883. {
  884.     return(s_really_send(s, buffer, buflen, flags, NULL));
  885.  
  886. int s_sendto (
  887.     Int4 s,
  888.     char *buffer,
  889.     Int4 buflen,
  890.     Int4 flags,
  891.     struct sockaddr *sa_to,
  892.     Int4 tolen)
  893. {
  894.     SocketPtr sp;
  895.     struct sockaddr_in *to=(struct sockaddr_in *)sa_to;
  896.  
  897.     if (s < 0 || s >= NUM_SOCKETS)
  898.         return (sock_err (EBADF));
  899.         
  900.     sp = sockets+s;
  901.     
  902.     if (! is_used (sp))
  903.         return (sock_err (EBADF));
  904.         
  905.     if (!goodptr(buffer))
  906.         return (sock_err (EFAULT));
  907.         
  908.     if (buflen <= 0)
  909.         return(sock_err(EINVAL));
  910.         
  911.     if (to != NULL && !goodptr(to))
  912.         return(sock_err(EFAULT));
  913.         
  914.     if (to != NULL && tolen < sizeof(struct sockaddr_in))
  915.         return(sock_err(EINVAL));
  916.  
  917.     return(s_really_send(s, buffer, buflen, flags, to));
  918. }
  919.  
  920. int s_sendmsg(Int4 s,struct msghdr *msg,Int4 flags) {
  921.     SocketPtr sp;
  922.     struct iovec *iov=NULL;
  923.     int tally=0,result,count;
  924.  
  925.     if (s < 0 || s >= NUM_SOCKETS)
  926.         return (sock_err (EBADF));
  927.         
  928.     sp = sockets+s;
  929.     
  930.     if (! is_used (sp))
  931.         return (sock_err (EBADF));
  932.     if (!goodptr(msg))
  933.         return (sock_err (EFAULT));
  934.     if ( msg->msg_name != NULL && !goodptr(msg->msg_name) ) 
  935.         return (sock_err (EFAULT));
  936.     if ( msg->msg_name != NULL && msg->msg_namelen < sizeof (struct sockaddr_in))
  937.         return (sock_err (EFAULT));
  938.     
  939.     count = msg->msg_iovlen;
  940.     iov = msg->msg_iov;
  941.     while ( count -- ) {
  942.         if ( !goodptr( iov ) )
  943.             return sock_err(EFAULT);
  944.         result= s_really_send(s, (char *)(iov->iov_base),
  945.                 (int)(iov->iov_len), flags,(struct sockaddr_in *)msg->msg_name);
  946.         if (result < 0)
  947.             return (sock_err(result));
  948.         iov++;
  949.         tally+=result;
  950.         }
  951.     return tally;
  952.     }
  953.  
  954. int s_really_send(
  955.     Int4 s,
  956.     char *buffer,
  957.     Int4 count,
  958.     Int4 flags,
  959.     struct sockaddr_in *to)
  960.     
  961.     {
  962.     SocketPtr    sp;
  963.     int            tally=0;
  964.  
  965. #if SOCK_DEBUG >= 2
  966.     dprintf("s_really_send: %d  %d bytes", s, count);
  967.     if (to != NULL)
  968.         dprintf(" to %08x/%d",to->sin_addr.s_addr,to->sin_port);
  969.     dprintf("\n");
  970. #endif
  971.     if (! sock_good_fd(s))
  972.         return(sock_err(EBADF));
  973.     sp = sockets+s;
  974.  
  975. #if SOCK_DEBUG >= 2
  976.     dprintf("state %d\n",sp->sstate);
  977.     dprintf("peer %08x/%d\n",sp->peer.sin_addr.s_addr,sp->peer.sin_port);
  978. #endif
  979.     
  980.     if (sock_nowrite(sp))
  981.         return(sock_err(ESHUTDOWN));
  982.  
  983.     switch(sp->protocol) 
  984.         {
  985.         case IPPROTO_UDP:
  986.             if (to == NULL && sp->sstate != SOCK_STATE_CONNECTED) 
  987.                 return(sock_err(ENOTCONN));
  988.             return(sock_udp_send(sp, to, buffer, count, flags));
  989.             break;
  990.             
  991.         case IPPROTO_TCP:
  992.             if (to != NULL) /* sendto */
  993.                 return(sock_err(EOPNOTSUPP));
  994.             if (sp->sstate != SOCK_STATE_CONNECTED) 
  995.                 return(sock_err(ENOTCONN));
  996.             return ( sock_tcp_send(sp, buffer, count,0 ));
  997.             break;
  998.         }
  999.     }
  1000.  
  1001.  
  1002. /*
  1003.  *    s_select(width, readfds, writefds, exceptfds, timeout)
  1004.  *
  1005.  *        select() examines the I/O descriptor  sets  whose  addresses
  1006.  *        are  passed  in  readfds,  writefds, and exceptfds to see if
  1007.  *        some of their descriptors are ready for reading,  ready  for
  1008.  *        writing, or have an exceptional condition pending.  width is
  1009.  *        the number of bits to be  checked  in  each  bit  mask  that
  1010.  *        represent  a file descriptor; the descriptors from 0 through
  1011.  *        width-1 in the  descriptor  sets  are  examined.   Typically
  1012.  *        width  has  the  value  returned by getdtablesize for the
  1013.  *        maximum number of file  descriptors.   On  return,  select
  1014.  *        replaces  the  given descriptor sets with subsets consisting
  1015.  *        of those descriptors that are ready for the requested opera-
  1016.  *        tion.  The total number of ready descriptors in all the sets
  1017.  *        is returned.
  1018.  *
  1019.  *        If timeout is not a NULL pointer,  it  specifies  a  maximum
  1020.  *        interval  to wait for the selection to complete.  If timeout
  1021.  *        is a NULL  pointer,  the  select  blocks  indefinitely.   To
  1022.  *        effect  a  poll,  the  timeout argument should be a non-NULL
  1023.  *        pointer, pointing to a zero-valued timeval structure.
  1024.  *
  1025.  *        Any of readfds, writefds, and exceptfds may be given as NULL
  1026.  *        pointers if no descriptors are of interest.
  1027.  *
  1028.  *        Using select to open a socket for reading is analogous  to
  1029.  *        performing an accept call.
  1030.  *
  1031.  *        select() returns the number of ready  descriptors  that  are
  1032.  *        contained  in  the  descriptor  sets,  or  -1  if  an  error
  1033.  *        occurred.  If the time limit expires then  select()  returns
  1034.  *        0.   If select() returns with an error the descriptor sets 
  1035.  *      will be unmodified.
  1036.  */
  1037. int s_select(
  1038.     Int4 width,
  1039.     fd_set *readfds,
  1040.     fd_set *writefds,
  1041.     fd_set *exceptfds,
  1042.     struct timeval *timeout)
  1043. {
  1044.     SocketPtr sp;
  1045.     long count;
  1046.     int s;
  1047.     long starttime, waittime;
  1048.     fd_set rd, wd, ed;
  1049.     int errorHappened;
  1050.  
  1051. #if SOCK_DEBUG >= 4
  1052.     dprintf("select:  socket: width %d\n",width);
  1053. #endif
  1054.     if (!goodptr(timeout) && timeout != NULL)
  1055.         return(sock_err(EFAULT));
  1056.     if (!goodptr(readfds) && readfds != NULL)
  1057.         return(sock_err(EFAULT));
  1058.     if (!goodptr(writefds) && writefds != NULL)
  1059.         return(sock_err(EFAULT));
  1060.     if (!goodptr(exceptfds) && exceptfds != NULL)
  1061.         return(sock_err(EFAULT));
  1062.         
  1063. #if SOCK_DEBUG >= 4
  1064.     dprintf("select: timeout %d sec, read %08x write %08x except %08x\n",
  1065.         (timeout ? timeout->tv_sec : 99999), 
  1066.         (readfds!=NULL ? *readfds : 0L),
  1067.         (writefds!=NULL ? *writefds : 0L),
  1068.         (exceptfds!=NULL ? *exceptfds : 0L));
  1069. #endif
  1070.  
  1071.     if (width > NUM_SOCKETS)    /* for now..xxx. */
  1072.         width = NUM_SOCKETS;
  1073.     count = 0;
  1074.     FD_ZERO(&rd);
  1075.     FD_ZERO(&wd);
  1076.     FD_ZERO(&ed);
  1077.  
  1078.     if (timeout) 
  1079.     {
  1080.         waittime = TVTOTICK(timeout->tv_sec,timeout->tv_usec);
  1081.         starttime = TickCount();
  1082.     }
  1083. #if SOCK_DEBUG >= 5
  1084.     dprintf("     starttime = %d(tics);  waittime = %d\n",starttime, waittime);
  1085. #endif
  1086.  
  1087.     do 
  1088.     {
  1089.         for (s = 0 , sp = sockets ; s < width ; ++s, ++sp) 
  1090.         {
  1091.             if (is_used(sp)) 
  1092.             {
  1093.                 errorHappened = 0;
  1094.                 
  1095.                 /* Check if there is data or connection available. */
  1096.                 if (readfds && FD_ISSET(s,readfds)) 
  1097.                 {
  1098.                         
  1099.                     switch(sp->protocol) 
  1100.                     {
  1101.                         case IPPROTO_UDP:
  1102.                             switch (sock_udp_can_recv(sp))
  1103.                             {
  1104.                                 case 1:
  1105.                                     FD_SET(s,&rd);
  1106.                                     ++count;
  1107.                                     break;
  1108.                                 case -1:
  1109.                                     errorHappened = 1;
  1110.                                     break;
  1111.                             }
  1112.                             break;
  1113.                 
  1114.                         case IPPROTO_TCP:
  1115.                     /* Must exit if stream is dead to avoid eternal lock up */
  1116.                             if (sock_tcp_can_read(sp) ) {
  1117.                                 FD_SET(s,&rd);
  1118.                                 ++count;
  1119.                                 } 
  1120.                             break;
  1121.                     }
  1122.                 }
  1123.                 if (writefds && FD_ISSET(s,writefds)) 
  1124.                 {
  1125.                     switch(sp->protocol) 
  1126.                     {
  1127.                         case IPPROTO_UDP:
  1128.                             switch (sock_udp_can_send(sp))
  1129.                             {
  1130.                                 case 1:
  1131.                                     FD_SET(s,&wd);
  1132.                                     ++count;
  1133.                                     break;
  1134.                                 case -1:
  1135.                                     errorHappened = 1;
  1136.                                     break;
  1137.                             }
  1138.                             break;
  1139.                 
  1140.                         case IPPROTO_TCP:
  1141.                             if (sock_tcp_can_write(sp))
  1142.                             {
  1143.                                 FD_SET(s,&wd);
  1144.                                 ++count;
  1145.                             }
  1146.                             break;
  1147.                     }
  1148.                 }
  1149.                 if (exceptfds && FD_ISSET(s,exceptfds)) 
  1150.                 {
  1151.                     if (errorHappened)  
  1152.                     {
  1153.                         FD_SET(s,&ed);
  1154.                         ++count;
  1155.                     }
  1156.                 }
  1157.             }
  1158.         }
  1159.         SPIN(false,SP_SELECT,0)
  1160.     } 
  1161.     while(count == 0 &&(timeout == 0 || TickCount() - starttime < waittime));
  1162.  
  1163.     if (readfds)             
  1164.         *readfds = rd;
  1165.     if (writefds)             
  1166.         *writefds = wd;
  1167.     if (exceptfds)             
  1168.         *exceptfds = ed;
  1169. #if SOCK_DEBUG >= 5
  1170.     dprintf("     elapsed = %d(tics)  count %d, read %08x write %08x except %08x\n",
  1171.         TickCount()-starttime,count,
  1172.         (readfds!=NULL ? *readfds : 0L),
  1173.         (writefds!=NULL ? *writefds : 0L),
  1174.         (exceptfds!=NULL ? *exceptfds : 0L));
  1175. #endif
  1176.     return(count);
  1177. }
  1178.     
  1179. /*
  1180.  *    s_getdtablesize()
  1181.  *
  1182.  *        The entries in the socket descriptor table are numbered with small
  1183.  *        integers starting at 0. getdtablesize returns the size of the 
  1184.  *        descriptor table.
  1185.  */
  1186. int s_getdtablesize()
  1187. {
  1188.     return(NUM_SOCKETS);
  1189. }
  1190.  
  1191. /*
  1192.  *    s_getsockname(s, name, namelen)
  1193.  *
  1194.  *        getsockname returns the current name for the  socket s.
  1195.  *        Namelen should  be initialized to
  1196.  *        indicate the amount of space pointed to by name.  On  return
  1197.  *        it contains the actual size of the name returned (in bytes).
  1198.  *        
  1199.  *        A 0 is returned if the call succeeds, -1 if it fails.
  1200.  */
  1201.  
  1202. int s_getsockname(
  1203.     Int4 s,
  1204.     struct sockaddr *name,
  1205.     Int4 *namelen)
  1206. {
  1207. #if SOCK_DEBUG >= 3
  1208.     dprintf("GETSOCKNAME: %d\n", s);
  1209. #endif
  1210.     if (! sock_good_fd(s))
  1211.         return(sock_err(EBADF));
  1212.  
  1213.     if (! goodptr(name))
  1214.         return(sock_err(EFAULT));
  1215.         
  1216.     if (*namelen < 0)
  1217.         return(sock_err(EINVAL));
  1218.  
  1219.     sock_copy_addr(&sockets[s].sa, name, namelen);
  1220.     return(0);
  1221. }
  1222.  
  1223. /*
  1224.  *    s_getpeername(s, name, namelen)
  1225.  *
  1226.  *        getpeername returns the name of the peer connected to socket s.
  1227.  *
  1228.  *        The  int  pointed  to  by the namelen parameter
  1229.  *        should be  initialized  to  indicate  the  amount  of  space
  1230.  *        pointed  to  by name.  On return it contains the actual size
  1231.  *        of the name returned (in bytes).  The name is  truncated  if
  1232.  *        the buffer provided is too small.
  1233.  *        
  1234.  *        A 0 is returned if the call succeeds, -1 if it fails.
  1235.  */
  1236. int s_getpeername(
  1237.     Int4 s,
  1238.     struct sockaddr *name,
  1239.     Int4 *namelen)
  1240. {
  1241.     SocketPtr sp;
  1242.  
  1243. #if SOCK_DEBUG >= 2
  1244.     dprintf("getpeername: socket %d\n", s);
  1245. #endif
  1246.     if (! sock_good_fd(s))
  1247.         return(sock_err(EBADF));        
  1248.  
  1249.     sp = sockets+s;
  1250.     if (! is_used (sp))
  1251.         return (sock_err (EBADF));
  1252.  
  1253.     if (! goodptr(name))
  1254.         return(sock_err(EFAULT));
  1255.         
  1256.     if (*namelen < 0)
  1257.         return(sock_err(EINVAL));
  1258.  
  1259.     if (sp->sstate != SOCK_STATE_CONNECTED) 
  1260.         return(sock_err(ENOTCONN));
  1261.  
  1262.     sock_copy_addr(&sockets[s].peer, name, namelen);
  1263.  
  1264.     return(0);
  1265. }
  1266.  
  1267. /*
  1268.  *    s_shutdown(s, how)
  1269.  *
  1270.  *        shutdown call causes all or part of a full-duplex
  1271.  *        connection on the socket s to be shut down.  If
  1272.  *        how is 0, then further receives will be disallowed.  If  how
  1273.  *        is  1,  then further sends will be disallowed.  If how is 2,
  1274.  *        then further sends and receives will be disallowed.
  1275.  *        
  1276.  *        A 0 is returned if the call succeeds, -1 if it fails.
  1277.  */
  1278. int s_shutdown(
  1279.     Int4 s,
  1280.     Int4 how)
  1281. {
  1282.     SocketPtr sp;
  1283.     
  1284. #if SOCK_DEBUG >= 2
  1285.     dprintf("shutdown: shutdown %d\n", s);
  1286. #endif
  1287.     if (! sock_good_fd(s))
  1288.         return(sock_err(EBADF));
  1289.     sp = sockets+s;
  1290.  
  1291.     switch(how) 
  1292.     {
  1293.         case 0 : 
  1294.             sp->status |= SOCK_STATUS_NOREAD;
  1295.             break;
  1296.             
  1297.         case 1 : 
  1298.             sp->status |= SOCK_STATUS_NOWRITE;
  1299.             break;
  1300.  
  1301.         case 2 :
  1302.             sp->status |= SOCK_STATUS_NOREAD | SOCK_STATUS_NOWRITE;
  1303.             break;
  1304.             
  1305.         default :
  1306.             return(sock_err(EINVAL));
  1307.     }
  1308.     return(0);
  1309. }
  1310.  
  1311. /*
  1312.  *    fcntl() operates on the socket s according to the order in cmd:
  1313.  *
  1314.  *        F_DUPFD    Like Dup. Returns a new descriptor which refers to the 
  1315.  *                same MacTCP stream as s and has the same descriptor 
  1316.  *                status.
  1317.  *
  1318.  *        F_GETFL    returns the descriptor status flags for s. The only
  1319.  *                flag supported is FNDELAY for non-blocking i/o.
  1320.  *
  1321.  *        F_SETFL    sets descriptor status flags for s. The only
  1322.  *                 flag supported is FNDELAY for non-blocking i/o.
  1323.  *
  1324.  *        A dup or F_DUPFD operation copies the descriptor status flags
  1325.  *        maintained by F_SETFL, but once the copy is done, the two are
  1326.  *        disjoint. THIS IS DIFFERENT FROM UNIX.
  1327.  *
  1328.  *        Upon successful completion, the value  returned  depends  on
  1329.  *        cmd as follows:
  1330.  *            F_DUPFD   A new descriptor.
  1331.  *             F_GETFL   Value of flags.
  1332.  *            F_SETFL   0.
  1333.  *
  1334.  *        On error, a value of -1  is returned and errno is set to indicate 
  1335.  *        the error.
  1336.  *
  1337.  *        EBADF           s is not a valid open descriptor.
  1338.  *
  1339.  *        EMFILE          cmd is F_DUPFD and socket descriptor table is full.
  1340.  *
  1341.  *        EINVAL          cmd is F_DUPFD and arg  is  negative  or
  1342.  *                      greater   than   the  maximum  allowable
  1343.  *                      number (see getdtablesize).
  1344.  */
  1345. int s_fcntl(
  1346.     Int4 s,
  1347.     unsigned Int4 cmd,
  1348.     Int4 arg)
  1349. {
  1350. #if SOCK_DEBUG >= 2
  1351.     dprintf("s_fcntl: %d\n", s);
  1352. #endif
  1353.  
  1354.     if (! sock_good_fd(s))
  1355.         return(sock_err(EBADF));
  1356.  
  1357.     switch(cmd) 
  1358.     {
  1359.         /*
  1360.          * Duplicate a socket.
  1361.          */
  1362.         case F_DUPFD : 
  1363.         {
  1364.             int s1;
  1365.             
  1366.             if (arg < 0 || arg >= NUM_SOCKETS)
  1367.                 return(sock_err(EINVAL));
  1368.             
  1369.             s1 = sock_free_fd(arg);
  1370.             if (s1 == -1)
  1371.                 return(sock_err(EMFILE));
  1372.             
  1373.             sock_dup_fd(s,s1);
  1374.             return(s1);
  1375.         }
  1376.         
  1377.         /*
  1378.          *  Get socket status.  This is like getsockopt().
  1379.          *  Only supported descriptor status is FNDELAY.
  1380.          */
  1381.         case F_GETFL : 
  1382.         {
  1383.             SocketPtr sp;
  1384.     
  1385.             sp = sockets+s;
  1386.             if (sp->nonblocking)
  1387.                 return(FNDELAY);
  1388.             else
  1389.                 return(0);
  1390.         }
  1391.         
  1392.         /*
  1393.          *  Set socket status.  This is like setsockopt().
  1394.          *  Only supported descriptor status is FNDELAY.
  1395.          */
  1396.         case F_SETFL : 
  1397.         {
  1398.             SocketPtr sp;
  1399.     
  1400.             sp = sockets+s;
  1401.             if (arg & FNDELAY)
  1402.                 sp->nonblocking = true;
  1403.             else
  1404.                 sp->nonblocking = false;
  1405.             
  1406.             return(0);
  1407.         }
  1408.     }
  1409. }
  1410.  
  1411. /*
  1412.  *    dup(s)
  1413.  *
  1414.  *    dup2(s, news)
  1415.  *
  1416.  *        dup() duplicates an existing socket descriptor.   The  argu-
  1417.  *        ment s is a small non-negative integer index in the per-
  1418.  *        process descriptor table.  The value must be less  than  the
  1419.  *        size  of  the  table, which is returned by getdtablesize(2).
  1420.  *        The new descriptor returned by the call is the  lowest  num-
  1421.  *        bered  descriptor  that  is not currently in use by the pro-
  1422.  *        cess.
  1423.  *
  1424.  *        In the second form  of  the  call,  the  value  of  the  new
  1425.  *        descriptor  desired  is  specified.   If  that descriptor is
  1426.  *        already in use, the descriptor is first deallocated as if  a
  1427.  *        close(2) call had been done first.
  1428.  *
  1429.  *        The value -1 is returned if an error occurs in either  call.
  1430.  *        The  external  variable  errno  indicates  the  cause of the
  1431.  *        error.
  1432.  *
  1433.  *        EBADF               s or  news is  not  a  valid  socket
  1434.  *                            descriptor.
  1435.  *
  1436.  *        EMFILE              Too many descriptors are active.
  1437.  */
  1438. int s_dup(
  1439.     Int4 s)
  1440. {
  1441.     return(s_fcntl(s, F_DUPFD, 0));
  1442. }
  1443.  
  1444. int s_dup2(
  1445.     Int4 s,
  1446.     Int4 s1)
  1447. {
  1448.     if (! sock_good_fd(s))
  1449.         return(sock_err(EBADF));
  1450.  
  1451.     if (s1 < 0 || s1 >= NUM_SOCKETS)
  1452.         return(sock_err(EBADF));
  1453.  
  1454.     if (is_used(sockets+s1))
  1455.     {
  1456.         if (s_close(s1) == -1)
  1457.             return(-1);
  1458.     }
  1459.     sock_dup_fd(s,s1);
  1460.     return(s1);
  1461. }
  1462.  
  1463.  
  1464. /*
  1465.  * s_Ioctl()
  1466.  */
  1467. int s_ioctl(
  1468.     Int4 d,
  1469.     Int4 request,
  1470.     Int4 *argp)
  1471. {
  1472.     struct    ifreq    *ifr;
  1473.     TCPiopb        *tpb;
  1474.     SocketPtr    sp;
  1475.     int            size;
  1476.  
  1477. #if SOCK_DEBUG >= 2
  1478.     dprintf("s_ioctl: %d, request %d\n", d,request);
  1479. #endif
  1480.  
  1481.     if (! sock_good_fd(d))
  1482.         return(sock_err(EBADF));
  1483.  
  1484.     sp = sockets+d;
  1485.     
  1486.     /*
  1487.      * Interpret high order word to find amount of data to be copied 
  1488.      * to/from the user's address space.
  1489.      */
  1490.     size =(request &~(IOC_INOUT | IOC_VOID)) >> 16;
  1491.     
  1492.     /*
  1493.      * Zero the buffer on the stack so the user gets back something deterministic.
  1494.      */
  1495.     if ((request & IOC_OUT) && size)
  1496.         bzero((void *)argp, size);
  1497.  
  1498.     ifr =(struct ifreq *)argp;
  1499.     switch(request) 
  1500.     {
  1501.         /* Non-blocking I/O */
  1502.         case FIONBIO:
  1503.             sp->nonblocking = *(Boolean *)argp;
  1504.             return(0);
  1505.  
  1506.          /* Number of bytes on input Q */
  1507.         case FIONREAD:
  1508.             tpb = sock_fetch_pb(sp);
  1509.             sp->dataavail = xTCPBytesUnread(sp);
  1510.             *(int *)argp=sp->dataavail;
  1511.             return 0;
  1512.  
  1513. #ifdef IOCTL_LATER    
  1514.         /*
  1515.          *    Get interface list.  Pass in buffer and buffer length.
  1516.          *    Returns list of length one of ifreq's 
  1517.          */
  1518.         case SIOCGIFCONF: 
  1519.         {    
  1520.             struct ifconf *ifc =(struct ifconf *)argp;
  1521.             struct ifreq *req = ifc->ifc_req;
  1522.             int reqlen;
  1523.             struct sockaddr_in *addr;
  1524.             
  1525.             /*
  1526.              *    Fill in req fields for the IF's name and local IP addr.
  1527.              */
  1528.             strncpy(req->ifr_name, myIFName, IFNAMSIZ);
  1529.             addr =(struct sockaddr_in *)&req->ifr_addr;
  1530.             addr->sin_family         = AF_INET;
  1531.             addr->sin_addr.s_addr    = myIPAddress;
  1532.             addr->sin_port            = 0;
  1533.             bzero(addr->sin_zero, sizeof(addr->sin_zero));
  1534.             ifc->ifc_len = sizeof(*req);
  1535.                     
  1536.             return(0);            
  1537.         }
  1538.  
  1539.         /*
  1540.          *    Returns MTU of specified IF.
  1541.          */
  1542.         case SIOCGIFMTU: 
  1543.         {    
  1544.             /* don't check IF specification - we only have one anyway */
  1545.             *(int *)ifr->ifr_data= xMaxMTU();
  1546.             return(0);
  1547.         }
  1548.         
  1549.         /*
  1550.          *    Returns local IP Address of IF
  1551.          */
  1552.         case SIOCGIFADDR: 
  1553.         {
  1554.             struct sockaddr_in *addr;
  1555.             
  1556.             /* don't check IF specification - we only have one anyway */
  1557.  
  1558.             addr = &ifr->ifr_addr;
  1559.             addr->sin_addr.s_addr = xIPAddr();
  1560.             addr->sin_family = AF_INET;
  1561.             return(0);
  1562.         }
  1563.  
  1564.         case SIOCGIFDSTADDR:         /* For point to point, which we don't support */
  1565.             return(sock_err(EINVAL));
  1566.  
  1567.         case SIOCGIFFLAGS:             /* Returns IF flags(none yet) */
  1568.             ifr->ifr_flags = 0;
  1569.             return(0);
  1570.             
  1571.         /*
  1572.          *    Return broadcast address - net address plus all ones in host part
  1573.          */
  1574.         case SIOCGIFBRDADDR:     
  1575.         {
  1576.             struct sockaddr_in *addr;
  1577.             
  1578.             /* don't check IF specification */
  1579.             /* we only have one and its broadcast  */
  1580.                 
  1581.             addr = &ifr->ifr_addr;
  1582.             addr->sin_addr.s_addr = xIPAddr() | ~xNetMask();
  1583.             return(0);
  1584.         }
  1585. #endif IOCTL_LATER    
  1586.         default :
  1587.             return(sock_err(EOPNOTSUPP));
  1588.     }
  1589. }
  1590.  
  1591. /*
  1592.  *    s_setsockopt()
  1593.  *
  1594.  *        Set socket options. None implemented. In Unix there are...
  1595.  *
  1596.  *          SO_REUSEADDR        toggle local address reuse
  1597.  *          SO_KEEPALIVE        toggle keep connections alive
  1598.  *          SO_DONTROUTE        toggle routing bypass for  outgoing
  1599.  *                              messages
  1600.  *          SO_LINGER           linger on close if data present
  1601.  *          SO_BROADCAST        toggle   permission   to   transmit
  1602.  *                              broadcast messages
  1603.  *          SO_OOBINLINE        toggle  reception  of   out-of-band
  1604.  *                              data in band
  1605.  *          SO_SNDBUF           set buffer size for output
  1606.  *          SO_RCVBUF           set buffer size for input
  1607.  *          SO_TYPE             get the type  of  the  socket  (get
  1608.  *                              only)
  1609.  *          SO_ERROR            get and clear error on  the  socket
  1610.  *                             (get only)
  1611.  */
  1612. int s_setsockopt(
  1613.     Int4 s,
  1614.     Int4 level,
  1615.     Int4 optname,
  1616.     char *optval,
  1617.     Int4 optlen)
  1618. {
  1619. #pragma unused(optval)
  1620. #pragma unused(optlen)
  1621.     SocketPtr sp;
  1622.  
  1623. #if SOCK_DEBUG >= 3
  1624.     dprintf("SETSOCKOPT:  socket: %d  option: %d  \n", s,optname);
  1625. #endif
  1626.     if (! sock_good_fd(s))
  1627.         return(sock_err(EBADF));
  1628.  
  1629.     sp = sockets+s;
  1630.  
  1631.     /*
  1632.      * demultiplex to socket option handlers at other protocol levels.(None
  1633.      * supported yet).
  1634.      */
  1635.     switch(level) 
  1636.     {
  1637.         case SOL_SOCKET :         /* socket level option */
  1638.             switch(optname) 
  1639.             {
  1640.                 default :
  1641.                     return(0);
  1642.             }
  1643.             break;
  1644.         case IPPROTO_TCP:
  1645.             switch(optname)
  1646.             {
  1647.                 default:
  1648.                     return(0);
  1649.             }
  1650.             break;
  1651.         default :
  1652.             return(sock_err(ENOPROTOOPT));
  1653.     }
  1654.     return(0);
  1655. }
  1656.  
  1657.  
  1658. /*
  1659.  * s_setspin() - define a routine to be called repeatedly when
  1660.  *                 socket routines are blocked (ie. spinning)
  1661.  *
  1662.  *                 pass a NULL pointer to turn off a previously
  1663.  *                 defined spin routine.
  1664.  */
  1665. int s_setspin(
  1666.     SpinFn routine)
  1667. {
  1668.     if (routine == NULL || goodptr(routine))
  1669.         {
  1670.         spinroutine = routine;
  1671.         return(0);
  1672.         }
  1673.     else
  1674.         return(sock_err(EFAULT));
  1675. }
  1676.  
  1677. /*
  1678.  * s_getspin() - returns current spinroutine
  1679.  */
  1680. SpinFn s_getspin()
  1681.     {
  1682.     return (spinroutine);
  1683.     }
  1684.     
  1685. int defaultSpin(spin_msg msg,long param)
  1686.     {
  1687. #pragma unused (msg,param)
  1688.     EventRecord evrec;
  1689.     
  1690.     WaitNextEvent(0, &evrec, 1 /* ticks */, NULL);
  1691.     return 0;        /* return non-zero to exit current routine */
  1692.     }
  1693.